package com.xci.core.aspect;

import com.xci.core.annotation.DataScope;
import com.xci.core.base.GMap;
import com.xci.core.domain.BaseEntity;
import com.xci.core.domain.BaseFilter;
import com.xci.core.exceptions.AppException;
import com.xci.core.helper.Helper;
import com.xci.core.internal.Sys;
import com.xci.sys.entity.SysUser;
import com.xci.sys.service.DeptService;
import com.xci.sys.service.RoleService;
import com.xci.sys.service.UserService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * 数据过滤处理
 */
@Aspect
public class DataScopeAspect {
    @Resource
    private UserService userService;//用户服务
    @Resource
    private DeptService deptService;//机构服务
    @Resource
    private RoleService roleService;//角色服务
    /**
     * 全部数据权限
     */
    public static final int DATA_SCOPE_ALL = 1;

    /**
     * 机构数据权限
     */
    public static final int DATA_SCOPE_DEPT = 2;

    /**
     * 机构及以下数据权限
     */
    public static final int DATA_SCOPE_DEPT_AND_CHILD = 3;

    /**
     * 自定数据权限
     */
    public static final int DATA_SCOPE_CUSTOM = 4;

    /**
     * 仅本人数据权限
     */
    public static final int DATA_SCOPE_SELF = 5;

    // 配置织入点
    @Pointcut("@annotation(com.xci.core.annotation.DataScope)")
    public void dataScopePointCut() {
    }

    @Before("dataScopePointCut()")
    public void doBefore(JoinPoint point) {
        handleDataScope(point);
    }

    private void handleDataScope(final JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        Object[] methodArgs = joinPoint.getArgs();
        Parameter[] methodParams = method.getParameters();
        if (methodArgs.length == 0) {
            throw new AppException("要启用数据权限必须要有参数,参数类型包括:BaseEntity,BaseFilter");
        }

        DataScope anScope = method.getAnnotation(DataScope.class);
        if (anScope == null) {
            return;
        }
        SysUser user = Sys.me().getCurrentUser();
        if (user == null || !user.getStatus()) {
            throw new AppException("您没有权限读取数据或者账号已停用");
        }
        if (user.getIsAdmin()) {// 如果是超级管理员，则不过滤数据
            return;
        }
        var dept = deptService.selectByUserId(user);
        if (dept == null || !dept.getStatus()) {
            throw new AppException(Helper.format("请给用户[{}][{}]指定机构", user.getAccount(), user.getId()));
        }
        var role = roleService.selectByUserId(user);
        if (role == null || !dept.getStatus()) {
            throw new AppException(Helper.format("请给用户[{}][{}]指定角色", user.getAccount(), user.getId()));
        }

        int deptScope = role.getDeptScope();
        if (DATA_SCOPE_ALL == deptScope) {//全部数据权限
            return;
        }

        Object filterObject = null;
        for (int i = 0; i < methodArgs.length; i++) {
            var args = methodArgs[i];
            var param = methodParams[i];
            if (param.getName().equals("filter") && (args instanceof BaseEntity || args instanceof BaseFilter)) {
                filterObject = args;
                break;
            }
        }
        if (filterObject != null) {
            // 1.数据范围 dataScope 2.用户主键 userId 3.机构主键 deptId
            // 4.角色主键 roleId 5.机构表别名 deptAlias 6.用户表别名 userAlias
            var map = GMap.newMap().append("dataScope", deptScope).append("userId", user.getId())
                    .append("deptId", dept.getId()).append("roleId", role.getId())
                    .append("deptAlias", anScope.deptAlias()).append("userAlias", anScope.userAlias());
            if (filterObject instanceof BaseFilter) {
                ((BaseFilter) filterObject).getParams().putAll(map);
            } else if (filterObject instanceof BaseEntity) {
                ((BaseEntity) filterObject).getParams().putAll(map);
            }
        } else {
            throw new AppException("要启用数据权限必须至少要有一个参数,参数类型包括:BaseEntity,BaseFilter中的任何一个");
        }
    }
}